package com.hh.workflow.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.hh.baseframework.util.Check;
import com.hh.baseframework.util.Convert;
import com.hh.baseframework.util.Json;
import com.hh.baseframework.util.MessageException;
import com.hh.baseframework.util.statics.StaticVar;
import com.hh.hibernate.dao.inf.IHibernateDAO;
import com.hh.hibernate.util.dto.HQLParamList;
import com.hh.system.service.impl.BaseService;
import com.hh.system.service.impl.HhXtDataService;
import com.hh.workflow.bean.HhWorkFlowInfo;
import com.hh.workflow.lis.UserTaskCreateEvent;
import com.hh.workflow.util.ImageUtil;
import com.hh.workflow.util.Static;

@Service
public class WorkFlowInfoService extends BaseService<HhWorkFlowInfo> {
	@Autowired
	private IHibernateDAO<HhWorkFlowInfo> dao;
	@Autowired
	private HhXtDataService hhXtDataService;

	public HhWorkFlowInfo save(HhWorkFlowInfo workFlowInfo, String imgxml)
			throws MessageException {
		if (!imgxml.endsWith("</output>")) {
			imgxml = "<output>" + imgxml + "</output>";
		}

		if (!workFlowInfo.getMxgraphXml().endsWith("</mxGraphModel>")) {
			workFlowInfo.setMxgraphXml("<mxGraphModel>"
					+ workFlowInfo.getMxgraphXml() + "</mxGraphModel>");
		}
		HttpServletRequest request = ServletActionContext.getRequest();
		String path = request.getContextPath();
		byte[] imageByte = ImageUtil.exportImage(2000, 2000,
				imgxml.replaceAll(path + "/jsp/", ""));
		workFlowInfo.setActivitiImg(imageByte);
		if (Check.isEmpty(workFlowInfo.getId())) {
			workFlowInfo.setId("WORK"
					+ UUID.randomUUID().toString().replace("-", ""));
			String activitiXml = getActivitiXml(workFlowInfo);
			workFlowInfo.setActivitiXml(activitiXml);
			dao.createEntity(workFlowInfo);
		} else {
			String activitiXml = getActivitiXml(workFlowInfo);
			workFlowInfo.setActivitiXml(activitiXml);
			dao.updateEntity(workFlowInfo);
		}
		return workFlowInfo;
	}

	public Map<String, Map<String, Object>> findCellObjectListByPdid(String id) {
		HhWorkFlowInfo hhWorkFlowInfo = new HhWorkFlowInfo();
		hhWorkFlowInfo.setPdid(id);
		Object[] objectMap = (Object[]) dao.findPropertys(hhWorkFlowInfo,
				new String[] { "cellObjectList", "rootObject" },
				new String[] { "pdid" });
		String object = Convert.toString(objectMap[0]);
		String rootObject = Convert.toString(objectMap[1]);
		Map<String, Object> rootmap = Json.toMap(rootObject);
		List<Map<String, Object>> mapList = Json.toMapList(object);
		Map<String, Map<String, Object>> returnMap = new HashMap<String, Map<String, Object>>();
		returnMap.put(Static.WORKFLOW_MAP_KEY, rootmap);
		for (Map<String, Object> map : mapList) {
			returnMap.put(map.get("id").toString(), map);
		}
		return returnMap;
	}

	private String getActivitiXml(HhWorkFlowInfo workFlowInfo) {
		Map<String, Object> rootMap = Json.toMap(workFlowInfo.getRootObject());
		List<Map<String, Object>> cellMaps = Json.toMapList(workFlowInfo
				.getCellObjectList());
		Document document = DocumentHelper.createDocument();
		document.setXMLEncoding("UTF-8");
		Element definitions = document.addElement("definitions",
				"http://www.omg.org/spec/BPMN/20100524/MODEL");
		definitions.addAttribute("typeLanguage",
				"http://www.w3.org/2001/XMLSchema");
		definitions.addAttribute("expressionLanguage",
				"http://www.w3.org/1999/XPath");
		definitions.addAttribute("targetNamespace",
				"http://www.activiti.org/test");
		definitions.addNamespace("xsi",
				"http://www.w3.org/2001/XMLSchema-instance");
		definitions.addNamespace("activiti", "http://activiti.org/bpmn");
		definitions.addNamespace("bpmndi",
				"http://www.omg.org/spec/BPMN/20100524/DI");
		definitions.addNamespace("omgdc",
				"http://www.omg.org/spec/DD/20100524/DC");
		definitions.addNamespace("omgdi",
				"http://www.omg.org/spec/DD/20100524/DI");
		addProcess(workFlowInfo, rootMap, cellMaps, definitions);

		return document.asXML().replaceAll("&gt;", ">").replaceAll("&lt;", "<")
				.replaceAll("&amp;", "&");
	}

	private void addProcess(HhWorkFlowInfo workFlowInfo,
			Map<String, Object> rootMap, List<Map<String, Object>> cellMaps,
			Element definitions) {
		Element process = definitions.addElement("process");
		Element documentationElements = process.addElement("documentation");
		documentationElements.addText("<![CDATA[ " + rootMap.get("description")
				+ " ]]>");
		process.addAttribute("id", workFlowInfo.getId());
		process.addAttribute("name", rootMap.get("label").toString());

		// ///////////////////////////////////////////////////////////////////////////////////
		Element bpmndi = DocumentHelper.createElement("bpmndi:BPMNDiagram");
		definitions.add(bpmndi);
		bpmndi.addAttribute("id", "BPMNDiagram_" + workFlowInfo.getId());

		Element bpmnPlane = DocumentHelper.createElement("bpmndi:BPMNPlane");
		bpmndi.add(bpmnPlane);

		bpmnPlane.addAttribute("bpmnElement", workFlowInfo.getId());
		bpmnPlane.addAttribute("id", "BPMNPlane_" + workFlowInfo.getId());

		addNodes(cellMaps, process, bpmnPlane);
	}

	private void addNodes(List<Map<String, Object>> cellMaps, Element process,
			Element bpmnPlane) {
		Map<String, Integer> activitySourceRefSize = new HashMap<String, Integer>();
		for (Map<String, Object> map : cellMaps) {
			String type = map.get("type").toString();
			String id = Convert.toString(map.get("sourceRef"));
			if ("sequenceFlow".equals(type)) {
				Integer size = activitySourceRefSize.get(id);
				if (size == null) {
					activitySourceRefSize.put(id, 1);
				} else {
					activitySourceRefSize.put(id, size + 1);
				}
			}
		}
		for (Map<String, Object> map : cellMaps) {
			String type = map.get("type").toString();
			String id = map.get("id").toString();
			String label = Convert.toString(map.get("label"));
			Element element = process.addElement(type);
			element.addAttribute("id", id);
			element.addAttribute("name", label);

			addBpmdDi(bpmnPlane, map);

			if ("sequenceFlow".equals(type)) {
				String sourceRef = Convert.toString(map.get("sourceRef"));
				String targetRef = Convert.toString(map.get("targetRef"));
				element.addAttribute("sourceRef", sourceRef);
				element.addAttribute("targetRef", targetRef);
				if (sourceRef.indexOf("startEvent") > -1
						|| activitySourceRefSize.get(sourceRef) == null
						|| activitySourceRefSize.get(sourceRef) == 1
				// || targetRef.indexOf("exclusiveGateway") > -1
				// || targetRef.indexOf("parallelGateway") > -1
				// || targetRef.indexOf("inclusiveGateway") > -1
				) {
				} else {
					String conditionType = Convert.toString(map
							.get("conditionType"));
					if ("1".equals(conditionType)) {
						Element conditionExpression = element
								.addElement("conditionExpression");
						conditionExpression.addText("<![CDATA[${" + "1=="
								+ targetRef + "}]]>");
					} else {
						String condition = Convert.toString(map
								.get("condition"));
						if (!Check.isEmpty(condition)) {
							Element conditionExpression = element
									.addElement("conditionExpression");
							conditionExpression.addText("<![CDATA[${"
									+ condition + "}]]>");
						}
					}
				}
			} else if ("startEvent".equals(type)) {

			} else if ("endEvent".equals(type)) {

			} else if ("userTask".equals(type)) {
				// element.addAttribute("activiti:candidateUsers",
				// "${candidateUsers_" + id + "}");
				Element extensionElements = element
						.addElement("extensionElements");
				Element taskListener = extensionElements
						.addElement("activiti:taskListener");
				taskListener.addAttribute("event", "create");
				taskListener.addAttribute("class",
						UserTaskCreateEvent.class.getName());
			} else if ("exclusiveGateway".equals(type)) {

			} else if ("parallelGateway".equals(type)) {

			} else if ("inclusiveGateway".equals(type)) {

			}
		}

	}

	private void addBpmdDi(Element bpmnPlane, Map<String, Object> map) {
		String type = map.get("type").toString();
		if ("userTask".equals(type)) {
			String id = Convert.toString(map.get("id"));
			String height = Convert.toString(map.get("height"));
			String width = Convert.toString(map.get("width"));
			String x = Convert.toString(map.get("x"));
			String y = Convert.toString(map.get("y"));
			Element bpmnShape = DocumentHelper
					.createElement("bpmndi:BPMNShape");
			bpmnPlane.add(bpmnShape);
			bpmnShape.addAttribute("bpmnElement", id);
			bpmnShape.addAttribute("id", "BPMNShape_" + id);
			Element bounds = DocumentHelper.createElement("omgdc:Bounds");
			bpmnShape.add(bounds);
			bounds.addAttribute("height", height);
			bounds.addAttribute("width", width);
			bounds.addAttribute("x", x);
			bounds.addAttribute("y", y);
		}

	}

	public HhWorkFlowInfo findObjectByDataId(String dataId) {
		HhWorkFlowInfo workFlowInfo = dao.findEntity(
				HhWorkFlowInfo.class,
				new HQLParamList().addCondition(
						Restrictions.eq("dataId", dataId)).addCondition(
						Restrictions.isNull("pdid")));
		return workFlowInfo;
	}

	public void deleteByIds(String ids) {
		List<String> deleteList = hhXtDataService.deleteByIds1(ids);
		dao.deleteEntity(HhWorkFlowInfo.class, "dataId", deleteList);
	}

	public void deleteByPdidList(List<String> idList) {
		dao.deleteEntity(HhWorkFlowInfo.class, "pdid", idList);
	}

	public static String[] copyPros = new String[] { "attachment", "comment" };

	public void copyWfToAct(Map<String, Object> activityMap,
			Map<String, Object> workflowMap) {
		Set<String> actKeySet = activityMap.keySet();
		if (Check.isEmpty(activityMap.get("href"))
				|| "null".equals(activityMap.get("href") + "")) {
			activityMap.put("href", workflowMap.get("href"));
			activityMap.put("hrefParams", workflowMap.get("hrefParams"));
		}
		for (String proStr : copyPros) {
			if (!actKeySet.contains(proStr)) {
				activityMap.put(proStr, workflowMap.get(proStr));
			}
		}

	}
}
